package services

import (
	"bsm/daos"
	"bsm/logger"
	"bsm/models"
	"bsm/utils"
	"fmt"
	"os"
	"path/filepath"
)

// 导出服务接口，命令行：soffice.exe --headless --convert-to pdf --outdir 目标路径  原文件

type ExportService interface {
	ExportProject(designcode string, designtype int) (string, error)
}

type exportServiceImpl struct {
	exportDao daos.ExportDao
	userDao   daos.UserDao
	xlsxTools utils.XlsxTools
}

var (
	ExcelTemplate = "template/temp.xlsx"
)

func NewExportService(exportDao daos.ExportDao, userDao daos.UserDao) ExportService {

	return &exportServiceImpl{
		exportDao: exportDao,
		userDao:   userDao,
		xlsxTools: utils.XlsxTools{},
	}
}

func (e *exportServiceImpl) fillApprovalData(dcode string, atype int) error {
	projectBase, err := e.exportDao.GetProjectBase(dcode, atype)
	if err != nil {
		logger.Errorf("导出时获取项目基本信息失败：%v", err)
		return fmt.Errorf("获取项目基本信息失败：%w", err)
	}

	user, err := e.userDao.GetUserByUserID(projectBase.Designer)
	if err != nil {
		logger.Errorf("导出时获取设计人失败：%v", err)
		return fmt.Errorf("获取设计人失败：%w", err)
	}
	projectBase.Designer = user.UserName

	user, err = e.userDao.GetUserByUserID(projectBase.Reviewer)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":      "service",
			"operation":  "fillApprovalData",
			"designcode": dcode,
			"atype":      atype,
		}).Errorf("获取审核人失败：%v", err)
		return fmt.Errorf("获取审核人失败：%w", err)
	}
	projectBase.Reviewer = user.UserName

	switch atype {
	case models.DesignType_Budget:
		projectBase.PreparationDate = projectBase.TimeBudget
	case models.DesignType_Settlement:
		projectBase.PreparationDate = projectBase.TimeSettle
	case models.DesignType_Audit:
		projectBase.PreparationDate = projectBase.TimeAudit
	}

	err = e.xlsxTools.WriteSingleRecord(projectBase)
	if err != nil {
		logger.Errorf("导出时填充立项数据失败：%v", err)
		return fmt.Errorf("填充立项数据失败：%w", err)
	}

	// sheetApproval := "工程立项"

	// e.xlsxTools.File.SetCellValue(sheetApproval, "B4", projectBase.Name)
	// e.xlsxTools.File.SetCellValue(sheetApproval, "H4", projectBase.DesignCode)

	// e.xlsxTools.File.SetCellValue(sheetApproval, "B5", projectBase.Initiator)

	// e.xlsxTools.File.SetCellValue(sheetApproval, "E5", dTime)
	// e.xlsxTools.File.SetCellValue(sheetApproval, "H5", projectBase.Designer)
	// e.xlsxTools.File.SetCellValue(sheetApproval, "B6", projectBase.ProjectOverview)
	// e.xlsxTools.File.SetCellValue(sheetApproval, "B10", projectBase.TechnicalAnalysis)

	// sheetCover := "封面"
	// e.xlsxTools.File.SetCellValue(sheetCover, "F10", projectBase.Initiator)
	// e.xlsxTools.File.SetCellValue(sheetCover, "J10", projectBase.ConstructionType)
	// e.xlsxTools.File.SetCellValue(sheetCover, "H15", projectBase.Reviewer)

	return nil
}

// fillTab3Data 专门用于填充ExportXlsxTab3数据
func (e *exportServiceImpl) fillTab3Data(dcode string, atype int) error {
	sheet := "（表三）甲"
	startRow := 6
	rowsPerPage := 28
	data, err := e.exportDao.GetLaborTable(dcode, atype)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":      "service",
			"operation":  "fillTab3Data",
			"designcode": dcode,
			"atype":      atype,
		}).Errorf("获取人工信息失败：%v", err)
		return fmt.Errorf("获取人工信息失败：%w", err)
	}

	dataCount := len(data)
	// 如果没有数据，直接返回
	if dataCount == 0 {
		return nil
	}

	// 转换为map数组
	mapData := make([]map[string]interface{}, dataCount)
	for i, item := range data {
		mapData[i] = map[string]interface{}{
			"code":      item.Code,
			"name":      item.Name,
			"unit":      item.Unit,
			"quantity":  item.Quantity,
			"mechanic":  item.Mechanic,
			"general":   item.General,
			"mechanics": "=F{row}*E{row}",
			"generals":  "=G{row}*E{row}",
		}
	}

	// 使用标准配置
	config := models.ExcelFillConfig{
		SheetName:   sheet,
		StartRow:    startRow,
		RowsPerPage: rowsPerPage,
		ColumnMap: map[string]string{
			"code":      "B",
			"name":      "C",
			"unit":      "D",
			"quantity":  "E",
			"mechanic":  "F",
			"general":   "G",
			"mechanics": "H",
			"generals":  "I",
		},
		Data:       mapData,
		WithHeader: false, // 假设模板已有表头
		AutoSize:   false,
	}

	err = e.xlsxTools.FillDataToExcel(config)
	if err != nil {
		return err
	}

	// 调整表尾求和公式
	sumCols := []string{"H", "I"} // 需要求和的 Mechanics, Generals 等列
	footerRow := startRow + dataCount
	if dataCount <= rowsPerPage {
		footerRow = startRow + rowsPerPage
	}

	if err := e.xlsxTools.RebuildFooterFormulas(sheet, startRow, footerRow, dataCount, sumCols); err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":      "service",
			"operation":  "fillTab3Data",
			"designcode": dcode,
			"atype":      atype,
		}).Errorf("调整表尾求和公式失败：%v", err)
		return err
	}
	return nil
}

// FillTab4Data 专门用于填充ExportXlsxTab4数据
func (e *exportServiceImpl) fillTab4Data(dcode string, atype int) error {
	sheet := "表四"
	startRow := 7
	rowsPerPage := 29
	data, err := e.exportDao.GetMaterialTable(dcode, atype)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":      "service",
			"operation":  "fillTab4Data",
			"designcode": dcode,
			"atype":      atype,
		}).Errorf("获取材料信息失败：%v", err)
		return fmt.Errorf("获取材料信息失败：%w", err)
	}

	dataCount := len(data)
	// 如果没有数据，直接返回
	if dataCount == 0 {
		return nil
	}

	// 转换为map数组
	mapData := make([]map[string]interface{}, len(data))
	for i, item := range data {
		mapData[i] = map[string]interface{}{
			"code":          item.Code,
			"name":          item.Name,
			"unit":          item.Unit,
			"quantity":      item.Quantity,
			"price":         item.Price,
			"tax":           "=F{row}*0.13",
			"price_inc_tax": "=F{row}+G{row}",
			"total_ex_tax":  "=F{row}*E{row}",
			"total_tax":     "=G{row}*E{row}",
			"total_inc_tax": "=H{row}+E{row}",
		}
	}

	// 使用标准配置
	config := models.ExcelFillConfig{
		SheetName:   sheet,
		StartRow:    startRow,
		RowsPerPage: rowsPerPage,
		ColumnMap: map[string]string{
			"code":          "B",
			"name":          "C",
			"unit":          "D",
			"quantity":      "E",
			"price":         "F",
			"tax":           "G",
			"price_inc_tax": "H",
			"total_ex_tax":  "I",
			"total_tax":     "J",
			"total_inc_tax": "K",
		},
		Data:       mapData,
		WithHeader: false, // 假设模板已有表头
		AutoSize:   false,
	}

	err = e.xlsxTools.FillDataToExcel(config)
	if err != nil {
		return err
	}

	// 调整表尾求和公式
	sumCols := []string{"I", "J", "K"} // 需要求和的 total 等列
	footerRow := startRow + dataCount
	if dataCount <= rowsPerPage {
		footerRow = startRow + rowsPerPage
	}
	if err := e.xlsxTools.RebuildFooterFormulas(sheet, startRow, footerRow, dataCount, sumCols); err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":      "service",
			"operation":  "fillTab4Data",
			"designcode": dcode,
			"atype":      atype,
		}).Errorf("调整表尾求和公式失败：%v", err)
		return err
	}
	return nil
}

// fillTab5Data 专门用于填充ExportXlsxTab5数据
func (e *exportServiceImpl) fillTab5Data(dcode string, atype int) error {
	sheet := "表五"
	startRow := 25
	rowsPerPage := 5
	data, err := e.exportDao.GetOtherFeeTable(dcode, atype)

	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":      "service",
			"operation":  "fillTab5Data",
			"designcode": dcode,
			"atype":      atype,
		}).Errorf("获取其他费用信息失败：%v", err)
		return fmt.Errorf("获取其他费用信息失败：%w", err)
	}
	if len(data) > 5 {
		rowsPerPage = 24
	}
	if len(data) > 0 {
		// 转换为map数组
		mapData := make([]map[string]interface{}, len(data))
		for i, item := range data {
			mapData[i] = map[string]interface{}{
				"serial_number": item.SerialNumber,
				"name":          item.Name,
				"basis":         item.Basis,
				"tax_excluded":  item.TaxExcluded,
				"tax":           item.Tax,
				"tax_included":  item.TaxIncluded,
				"remark":        item.Remark,
			}
		}

		// 使用标准配置
		config := models.ExcelFillConfig{
			SheetName:   sheet,
			StartRow:    startRow,
			RowsPerPage: rowsPerPage,
			ColumnMap: map[string]string{
				"serial_number": "A",
				"name":          "B",
				"basis":         "C",
				"tax_excluded":  "D",
				"tax":           "E",
				"tax_included":  "F",
				"remark":        "G",
			},
			Data:       mapData,
			WithHeader: false, // 假设模板已有表头
			AutoSize:   false,
		}

		err = e.xlsxTools.FillDataToExcel(config)
		if err != nil {
			logger.WithFields(map[string]interface{}{
				"layer":      "service",
				"operation":  "fillTab5Data",
				"designcode": dcode,
				"atype":      atype,
			}).Errorf("填充其他费用数据失败：%v", err)
			return err
		}
	}
	// 调整表尾求和公式
	sumCols := []string{"D", "E", "F"} // 需要求和的 total 等列
	totalRow := 23
	dataEndrow := len(data) + startRow - 1
	for _, colName := range sumCols {
		totalCell := fmt.Sprintf("%s%d", colName, totalRow)
		sumFormula := fmt.Sprintf("=SUM(%s6:%s22)+SUM(%s%d:%s%d)", colName, colName, colName, startRow, colName, dataEndrow)
		if err := e.xlsxTools.File.SetCellFormula(sheet, totalCell, sumFormula); err != nil {
			logger.WithFields(map[string]interface{}{
				"layer":      "service",
				"operation":  "fillTab5Data",
				"designcode": dcode,
				"atype":      atype,
			}).Errorf("设置合计公式失败 %s: %v", totalCell, err)
			return fmt.Errorf("设置合计公式失败 %s: %w", totalCell, err)
		}
		e.xlsxTools.File.CalcCellValue(sheet, totalCell)
	}

	return nil
}

func (e *exportServiceImpl) ExportProject(designcode string, designtype int) (string, error) {
	currentDir, err := os.Getwd()
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":      "service",
			"operation":  "SvcExportProject",
			"designcode": designcode,
			"designtype": designtype,
		}).Errorf("获取当前目录失败：%v", err)
		return "", fmt.Errorf("获取当前目录失败：%w", err)

	}

	file := filepath.Join(currentDir, ExcelTemplate)

	err = e.xlsxTools.NewXlsxTools(file, designtype)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":      "service",
			"operation":  "SvcExportProject",
			"designcode": designcode,
			"designtype": designtype,
		}).Errorf("打开文件失败：%v", err)
		return "", fmt.Errorf("打开文件失败：%w", err)
	}

	xt := e.xlsxTools
	err = xt.RemoveExternalLinks()
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":      "service",
			"operation":  "SvcExportProject",
			"designcode": designcode,
			"designtype": designtype,
		}).Errorf("删除外部链接失败：%v", err)
		return "", fmt.Errorf("删除外部链接失败：%w", err)
	}

	defer xt.File.Close()

	err = e.fillApprovalData(designcode, designtype)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":      "service",
			"operation":  "SvcExportProject",
			"designcode": designcode,
			"designtype": designtype,
		}).Errorf("填充基本数据失败：%v", err)
		return "", fmt.Errorf("填充基本数据失败：%w", err)
	}

	err = e.fillTab3Data(designcode, designtype)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":      "service",
			"operation":  "SvcExportProject",
			"designcode": designcode,
			"designtype": designtype,
		}).Errorf("填充表三数据失败：%v", err)
		return "", fmt.Errorf("填充表三数据失败：%w", err)
	}

	err = e.fillTab4Data(designcode, designtype)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":      "service",
			"operation":  "SvcExportProject",
			"designcode": designcode,
			"designtype": designtype,
		}).Errorf("填充表四数据失败：%v", err)
		return "", fmt.Errorf("填充表四数据失败：%w", err)
	}

	err = e.fillTab5Data(designcode, designtype)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":      "service",
			"operation":  "SvcExportProject",
			"designcode": designcode,
			"designtype": designtype,
		}).Errorf("填充表五数据失败：%v", err)
		return "", fmt.Errorf("填充表五数据失败：%w", err)
	}

	dcodefile := filepath.Join(currentDir, "/export/"+designcode+".xlsx")
	err = xt.SaveFileWithRecalc(dcodefile)
	// err = xt.SaveFile(dcodefile)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":      "service",
			"operation":  "SvcExportProject",
			"designcode": designcode,
			"designtype": designtype,
		}).Errorf("保存文件失败：%v", err)
		return "", fmt.Errorf("保存文件失败：%w", err)
	}

	return dcodefile, nil
}
